package sg.edu.nus.iss.vmcs.customer;

import java.util.ArrayList;
import java.util.List;

import sg.edu.nus.iss.vmcs.machinery.MachineryController;
import sg.edu.nus.iss.vmcs.store.CashStore;
import sg.edu.nus.iss.vmcs.store.Coin;
import sg.edu.nus.iss.vmcs.store.Store;

/*
 * Copyright 2003 ISS.
 * The contents contained in this document may not be reproduced in any
 * form or by any means, without the written permission of ISS, other
 * than for the purpose for which it has been supplied.
 *
 */

/**
 * This control object manages the input and storage of Coins
 */
public class CoinReceiver {

	/**
	 * List of the Coins entered during transaction
	 */
	private List<Coin> coins;
	
	/**
	 * Total amount of money entered so far during current transaction
	 */
	private int totalInserted;
	
	/**
	 * Transaction controller controlling this control object
	 */
	private TransactionController transactionController;
	
	/**
	 * This constructor creates an instance of the object
	 * 
	 * @param transactionController
	 *            Transaction controller controlling this control object
	 */
	public CoinReceiver(TransactionController transactionController) {
		this.transactionController = transactionController;
		
		// initialize coins
		this.coins = new ArrayList<Coin>();;
		this.totalInserted = 0;
	}
	
	/**
	 * This operation will activate the Coin Input Box so that further coins 
	 * can be received
	 * 
	 * @author justin
	 * 		- updated with adapter pattern.
	 */
	
	public void continueReceive() {
		System.out.println("CoinReceiver::continueReceive()");
		this.transactionController.getCoinInputAdapter().updateStatus(true);
	}
	
	/**
	 * When a Coin is received the following will occur: 
	 * 
	 * 1. The Coin Input Box will be instructed to become deactivated. 
	 * 2. The weight of the Coin will be sent to the object Coin for it to 
	 * determine the denomination and value. 
	 * 3. The Total Money Inserted Display will be updated. 
	 * 4. If an invalid coin is entered, the Invalid Coin Display will be 
	 * instructed to display INVALID COIN. 
	 * 5. The Transaction Controller will be informed to process the current 
	 * transaction based on the money received
	 * 
	 * @param weight
	 *            The weight of the coin inserted
	 */
	public void receiveCoin(double weight) {
		this.transactionController.getCustomerPanel().getInvalidCoinDisplay().setState(false);
		this.transactionController.getCustomerPanel().getRefundChangeTrayDisplay().setValue("0 C");
		System.out.println("CoinReceiver::receiveCoin()");
		this.transactionController.getCoinInputAdapter().updateStatus(false);		
		CashStore cashStore = (CashStore) this.transactionController.getMainController().getStoreController().getStore(Store.CASH);
		Coin coin = new Coin(0, weight);
		int index = cashStore.findCashStoreIndex(coin);
		
		if (index != -1) {
			// valid coin
			coin = (Coin) cashStore.getStoreItem(index).getContent();
			int value = coin.getValue();
			
			// update total inserted
			this.totalInserted += value;
			this.transactionController.getCustomerPanel().getTotalMoneyInsertedDisplay().setValue(this.totalInserted + " C");
			this.coins.add(coin);
		}
		else {
			// invalid coin
			this.transactionController.getCustomerPanel().getInvalidCoinDisplay().setState(true);
		}
		this.transactionController.getCustomerPanel().getRefundChangeTrayDisplay().setValue("0 C");
		this.transactionController.processMoneyReceived(this.totalInserted);
	}
	
	/**
	 * This operation handles the refunding of Coins entered so far to the Customer.
	 */
	public void refundCash() {
		this.coins = new ArrayList<Coin>();
		this.transactionController.getCustomerPanel().getRefundChangeTrayDisplay().setValue(totalInserted + " C");
		this.totalInserted = 0;
		this.transactionController.getCustomerPanel().getTotalMoneyInsertedDisplay().setValue(totalInserted + " C");
		this.transactionController.getCustomerPanel().getInvalidCoinDisplay().setState(false);
	}
	
	/**
	 * This operation activates or deactivates the Coin Input Box
	 * 
	 * 
	 * @param active Boolean indicating whether active
	 * 
	 * @author justin
	 * 		- updated with adapter pattern.
	 */
	public void setActive(boolean active) {
		System.out.println("CoinReceiver::setActive()");
		this.transactionController.getCoinInputAdapter().updateStatus(active);
	}

	/**
	 * Commence receiving a series of coins. To do this the Coin Receiver
	 * instructs the Coin Input Box to become activated. It also updates the
	 * Total Money Inserted Display on the Customer Panel
	 * 
	 */
	public void startReceive() {
		setActive(true);
		this.transactionController.getCustomerPanel().getTotalMoneyInsertedDisplay().setValue("0 C");
	}
	
	/**
	 * This operation will deactivate the Coin Input Box in order to stop 
	 * receiving coins
	 */
	public void stopReceive() {
		setActive(false);
	}
	
	/**
	 * Instruct the Cash Store to update its totals and then re-set the Total 
	 * Money Inserted Display to zero.
	 * 
	 * @return TRUE if operation is successful
	 */
	public boolean storeCash() {
		MachineryController machineryController = this.transactionController
				.getMainController().getMachineryController();
		try {
			for (int i = 0; i < coins.size(); i++) {
				//if(i == 2){i=22;}
				machineryController.storeCoin(coins.get(i));
			}
		} catch (Exception e) {
			this.transactionController.terminateFault(TransactionController.FAULT_TYPE_STORE_COIN);
			return false;
		}
		
		this.transactionController.getCustomerPanel().getTotalMoneyInsertedDisplay().setValue("0 C");
		coins = new ArrayList<Coin>();
		this.totalInserted = 0;
		
		return true;
		
	}

	public int getTotalInserted() {
		return totalInserted;
	}

	public TransactionController getTransactionController() {
		return transactionController;
	}
	
	
	
}
